package com.carleasoft.mps.exam.business.questions.service.Impl;

import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.core.exceptions.BusinessException;
import com.carleasoft.mps.core.user.ThreadUserContext;
import com.carleasoft.mps.core.user.UserCacheData;
import com.carleasoft.mps.core.utils.IBeanUtil;
import com.carleasoft.mps.exam.business.questions.bean.entity.EOption;
import com.carleasoft.mps.exam.business.questions.bean.entity.ETopic;
import com.carleasoft.mps.exam.business.questions.bean.po.DownloadPo;
import com.carleasoft.mps.exam.business.questions.bean.po.ETopicAddOrEditPo;
import com.carleasoft.mps.exam.business.questions.bean.po.ETopicPageQueryPo;
import com.carleasoft.mps.exam.business.questions.bean.vo.ETopicDetailVo;
import com.carleasoft.mps.exam.business.questions.bean.vo.ETopicVo;
import com.carleasoft.mps.exam.business.questions.constants.ExceptionQuestionsEnum;
import com.carleasoft.mps.exam.business.questions.dao.ETopicMapper;
import com.carleasoft.mps.exam.business.questions.service.EOptionService;
import com.carleasoft.mps.exam.business.questions.service.ETopicService;
import com.carleasoft.mps.exam.common.feign.FastDfsFeignService;
import com.carleasoft.mps.excel.utils.ConvertTemplatePath;
import com.carleasoft.mps.excel.utils.ExcelUtils;
import org.apache.http.entity.ContentType;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 题目主表 服务实现类
 * </p>
 *
 * @author fan
 * @since 2023-05-17
 */
@Service
public class ETopicServiceImpl extends ServiceImpl<ETopicMapper, ETopic> implements ETopicService {

    @Autowired
    private EOptionService optionService;
    @Autowired
    private FastDfsFeignService fastDfsFeignService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean eTopicAdd(ETopicAddOrEditPo eTopicAddOrEditPo) {
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        ETopic eTopic = new ETopic();
        BeanUtils.copyProperties(eTopicAddOrEditPo,eTopic);
        String code = UUID.randomUUID().toString().replaceAll("-", "");
        eTopic.setTopicCode(code);
        eTopic.setCreatePersonCode(user.getUserCode());
        eTopic.setCreatePersonName(user.getUserName());
        eTopic.setCreateTime(LocalDateTime.now());
        eTopic.setUpdatePersonCode(user.getUserCode());
        eTopic.setUpdatePersonName(user.getUserName());
        eTopic.setUpdateTime(LocalDateTime.now());
        List<EOption> optionList = eTopicAddOrEditPo.getOptionList();
        if (!optionList.isEmpty()){
            optionList.stream().forEach(a->{
                a.setTopicCode(code);
            });
            optionService.saveBatch(optionList);
        }
        this.save(eTopic);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean eTopicEdit(ETopicAddOrEditPo eTopicAddOrEditPo) {
        IBeanUtil.paramVerify(eTopicAddOrEditPo,"topicCode");
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        ETopic eTopic = new ETopic();
        BeanUtils.copyProperties(eTopicAddOrEditPo,eTopic);
        String code = eTopicAddOrEditPo.getTopicCode();
        eTopic.setTopicCode(code);
        eTopic.setUpdatePersonCode(user.getUserCode());
        eTopic.setUpdatePersonName(user.getUserName());
        eTopic.setUpdateTime(LocalDateTime.now());
        List<EOption> optionList = eTopicAddOrEditPo.getOptionList();
        optionService.remove(new QueryWrapper<EOption>().eq("TOPIC_CODE",eTopicAddOrEditPo.getTopicCode()));
        if (!optionList.isEmpty()){
            optionList.stream().forEach(a->{
                a.setTopicCode(code);
            });
            optionService.saveBatch(optionList);
        }
        this.update(eTopic,new QueryWrapper<ETopic>().eq("TOPIC_CODE",eTopicAddOrEditPo.getTopicCode()));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean eTopicDelete(ETopic eTopic) {
        IBeanUtil.paramVerify(eTopic,"topicCode");
        this.remove(new QueryWrapper<ETopic>().eq("TOPIC_CODE",eTopic.getTopicCode()));
        optionService.remove(new QueryWrapper<EOption>().eq("TOPIC_CODE",eTopic.getTopicCode()));
        return true;
    }

    @Override
    public Page<ETopicVo> eTopicPageQuery(ETopicPageQueryPo eTopicPageQueryPo) {
        Page page = new Page(eTopicPageQueryPo.getCurrent(),eTopicPageQueryPo.getSize());
        return this.baseMapper.eTopicPageQuery(page,eTopicPageQueryPo);
    }

    @Override
    public ETopicDetailVo eTopicDetail(ETopic eTopic) {
        IBeanUtil.paramVerify(eTopic,"topicCode");
        ETopicDetailVo eTopicDetailVo = new ETopicDetailVo();
        ETopic one = this.getOne(new QueryWrapper<ETopic>().eq("TOPIC_CODE", eTopic.getTopicCode()));
        BeanUtils.copyProperties(one,eTopicDetailVo);
        eTopicDetailVo.setOptionList(optionService.list(new QueryWrapper<EOption>().eq("TOPIC_CODE", eTopic.getTopicCode())));
        return eTopicDetailVo;
    }

    @Override
    public boolean download(DownloadPo downloadPo, HttpServletResponse response) {
        Map<String, Object> map = new HashMap<>();
        Integer type = downloadPo.getType();//1-单选题模板 2-多选题模板 3-判断题模板 4-主观题模板
        String path = "";
        if (type==1){ //singleChoiceTemplate
            path = "\\templates\\singleChoiceTemplate.xls";
        }
        if (type==2){//multipleChoiceTemplate
            path = "\\templates\\multipleChoiceTemplate.xls";
        }
        if (type==3){//trueOrFalseQuestionsTemplate
            path = "\\templates\\trueOrFalseQuestionsTemplate.xls";
        }
        if (type==4){//objectiveItemTemplate
            path = "\\templates\\objectiveItemTemplate.xls";
        }
        TemplateExportParams templatePath = new TemplateExportParams(ConvertTemplatePath.convertTemplatePath(path));
        try {
            if (type==0){
                ExcelUtils.exportExcel(templatePath, map, "单选题导入模板", response);
            }
            if (type==1){
                ExcelUtils.exportExcel(templatePath, map, "多选题导入模板", response);
            }
            if (type==2){
                ExcelUtils.exportExcel(templatePath, map, "判断题导入模板", response);
            }
            if (type==3){
                ExcelUtils.exportExcel(templatePath, map, "主观题导入模板", response);
            }
        } catch (IOException e) {
            throw new BusinessException(ExceptionQuestionsEnum.TEMP_ERROR);
        }
        return true;
    }

    @Override
    public List<ETopicDetailVo> parse(DownloadPo downloadPo,MultipartFile file) {
        List<ETopicDetailVo> eTopicDetailVoList = new LinkedList<>();
        Integer type = downloadPo.getType();//1-单选题模板 2-多选题模板 3-判断题模板 4-主观题模板
//        List<Map<String,Object>> fl = new ArrayList<>();
//        try {
//            fl = ExcelUtils.importExcel(file, Map.class);
//            if (CollUtil.isEmpty(fl)) {
//                throw new BusinessException(ExceptionQuestionsEnum.PARSE_ERROR);
//            }
//            fl = fl.stream().filter(purchaseListEntity -> !ObjectSelfUtil.isAllFieldNull(purchaseListEntity)).collect(Collectors.toList());
//            if (CollUtil.isEmpty(fl)) {
//                throw new BusinessException(ExceptionQuestionsEnum.PARSE_ERROR);
//            }
//        } catch (IOException e) {
//            throw new BusinessException(ExceptionQuestionsEnum.PARSE_ERROR);
//        }
//        if(type==1){
//
//        }
//        if(type==2){
//
//        }
//        if(type==3){
//
//        }
//        if(type==4){
//
//        }


        //获取图片数据
        Map<String, PictureData> map = null;
        try {
            map = getPictureFromExcel(file, 1);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //根据图片行列位置获取图片
        PictureData picData = (PictureData)map.get("0"+"-"+0);
        //后缀名
        String extension = picData.suggestFileExtension();
        byte[] data = picData.getData();
        try {
            MultipartFile multipartFile = new MockMultipartFile(
                    "file",
                    "filename",
                    ContentType.APPLICATION_OCTET_STREAM.toString(),
                    new ByteArrayInputStream(data)
            );
            //todo 存图片到fastdfs
            String upload = fastDfsFeignService.upload(multipartFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("D:\\A\\" + "picture." + extension);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            out.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 获取excel表中的图片
     */
    public static Map<String, PictureData> getPictureFromExcel(MultipartFile file, int sheetNum) throws EncryptedDocumentException, IOException {

        //获取图片PictureData集合
        String fileName = file.getOriginalFilename();
        Workbook workbook = null;
        if (StrUtil.isEmpty(fileName)) {
            return null;
        }
        FileInputStream fileInputStream = (FileInputStream) file.getInputStream();
        if (fileName.endsWith("xls")) {
            //2003
            workbook = new HSSFWorkbook(fileInputStream);
            HSSFSheet sheet = (HSSFSheet) workbook.getSheetAt(sheetNum - 1);
            Map<String, PictureData> pictures = getPictures(sheet);
            return pictures;
        } else if (fileName.endsWith("xlsx")) {
            //2007
            workbook = new XSSFWorkbook(fileInputStream);
            XSSFSheet sheet = (XSSFSheet) workbook.getSheetAt(sheetNum - 1);
            Map<String, PictureData> pictures = getPictures(sheet);
            return pictures;
        }
        return new HashMap();
    }
    /**
     * 获取图片和位置 (xls版)
     */
    public static Map<String, PictureData> getPictures (HSSFSheet sheet) throws IOException {
        Map<String, PictureData> map = new HashMap<String, PictureData>();
        List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
        for (HSSFShape shape : list) {
            if (shape instanceof HSSFPicture) {
                HSSFPicture picture = (HSSFPicture) shape;
                HSSFClientAnchor cAnchor = picture.getClientAnchor();
                PictureData pdata = picture.getPictureData();
                String key = cAnchor.getRow1() + "-" + cAnchor.getCol1(); // 行号-列号
                map.put(key, pdata);
            }
        }
        return map;
    }

    /**
     * 获取图片和位置 (xlsx版)
     */
    public static Map<String, PictureData> getPictures (XSSFSheet sheet) throws IOException {
        Map<String, PictureData> map = new HashMap<String, PictureData>();
        List<POIXMLDocumentPart> list = sheet.getRelations();
        for (POIXMLDocumentPart part : list) {
            if (part instanceof XSSFDrawing) {
                XSSFDrawing drawing = (XSSFDrawing) part;
                List<XSSFShape> shapes = drawing.getShapes();
                for (XSSFShape shape : shapes) {
                    XSSFPicture picture = (XSSFPicture) shape;
                    XSSFClientAnchor anchor = picture.getPreferredSize();
                    CTMarker marker = anchor.getFrom();
                    String key = marker.getRow() + "-" + marker.getCol();
                    map.put(key, picture.getPictureData());
                }
            }
        }
        return map;
    }

    @Override
    public boolean importETopic(List<ETopicAddOrEditPo> eTopicAddOrEditPos) {
        return true;
    }
}
